﻿using IOP.SgrA;
using IOP.SgrA.SilkNet.Vulkan;
using Microsoft.Extensions.Logging;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.Text;

namespace VkSample91
{
    public class PresentGroupRendingMiddleware : IProductionLineMiddleware<PrimaryVulkanRenderGroup>
    {
        public void Invoke(PrimaryVulkanRenderGroup group, RenderingProductionLineDelegate<PrimaryVulkanRenderGroup> next)
        {
			try
			{
                var queue = group.WorkQueues[0].Queue;
                var cmdBuffer = group.PrimaryCommandBuffer;
                var semaphores = group.Semaphores;
                var pass = group.RenderPass;
                var fence = group.Fences;
                var pieline = group.Pipeline;
                var lDevice = group.LogicDevice;

                var tex = group.Pipeline.GetPipelineTexture(0, 1);
                var imageTex = tex.TextureData as VulkanImageTextureData;
                var image = imageTex.ImageInfo.Image;
                var range = imageTex.ImageInfo.ImageView.CreateOption.SubresourceRange;

                int index = 0;
                Span<IOP.SgrA.SilkNet.Vulkan.WriteDescriptorSet> writes = new IOP.SgrA.SilkNet.Vulkan.WriteDescriptorSet[2];
                foreach (var item in group.Pipeline.PipelineTextures) writes[index++] = item.Value.WriteDescriptorSet;
                lDevice.UpdateDescriptorSets(writes, null);

                VulkanFrameBuffer framebuffer = group.RenderPass.GetFramebuffer(group.CurrentFrame);
                cmdBuffer.Reset();
                cmdBuffer.Begin();
                cmdBuffer.BeginRenderPass(pass, framebuffer, pass.BeginOption, SubpassContents.Inline);
                cmdBuffer.BindPipeline(PipelineBindPoint.Graphics, group.Pipeline);
                var viewPort = group.Camera.Viewport;
                cmdBuffer.SetViewport(new Viewport(viewPort.X, viewPort.Y, viewPort.Width, viewPort.Height, viewPort.MinDepth, viewPort.MaxDepth));
                cmdBuffer.SetScissor(new Rect2D(null, new Extent2D((uint)viewPort.Width, (uint)viewPort.Height)));

                var set = group.Pipeline.GetPipelineDescriptorSet(0);
                cmdBuffer.BindDescriptorSets(PipelineBindPoint.Graphics, pieline.PipelineLayout, 0, null, set);

                foreach (var item in group.GetContexts())
                {
                    group.ItemProductionLine(item);
                }
                cmdBuffer.EndRenderPass();
                cmdBuffer.TransitionImageLayout(image, ImageLayout.General, ImageLayout.TransferDstOptimal, range);
                cmdBuffer.ClearColorImage(image, ImageLayout.TransferDstOptimal,
                    new ClearColorValue(0, 0, 0, 0), range);
                cmdBuffer.TransitionImageLayout(image, ImageLayout.TransferDstOptimal, ImageLayout.General, range);
                cmdBuffer.End();
                var submitInfo = new SubmitOption
                {
                    WaitDstStageMask = new PipelineStageFlags[] { PipelineStageFlags.PipelineStageColorAttachmentOutputBit, PipelineStageFlags.PipelineStageColorAttachmentOutputBit },
                    WaitSemaphores = new Semaphore[] { semaphores[0], semaphores[1] },
                    Buffers = new CommandBuffer[] { cmdBuffer.RawHandle },
                    SignalSemaphores = new Semaphore[] { semaphores[2] }
                };
                lDevice.Submit(queue, fence[0], submitInfo);
                Result r = Result.Timeout;
                do
                {
                    r = group.LogicDevice.WaitForFences(fence, true, 100000000);
                } while (r == Result.Timeout);
                group.LogicDevice.ResetFences(fence);
            }
			catch (Exception e)
			{
                group.Logger.LogError(e.Message + "\r\n" + e.StackTrace);
                group.Disable();
            }
        }
    }
}
